package model.audio;

public class DBAnalysis{

	private float sampleRate;
	
	public static final float[] OCTAVE_BAND={31.5f,63,125,250,500,1000,2000,4000,8000};   //倍频程带
	
	public DBAnalysis(float sampleRate){
		this.sampleRate=sampleRate;
	}
	
	public double getDBA(int[] data){    //data是采样到量化后的数据   data要先转化 16bits时20微帕斯卡被量化为1
		int N=data.length;             //fft点数 =2^n
		Complex[] x=toComplex(data);//初始化复数数组
		Complex[] y=FFT.fft(x);        //得到fft计算结果
		Complex[] z=getHalfPoints(y);
		double[] A=getAbs(z);       //幅度值		
        double dBs[]=getDBs(A,N);
        int band_num=OCTAVE_BAND.length;
        double dBAs[]=new double[band_num];
        double sum=0.0;           
        for(int i=0;i<band_num;i++){
        	dBAs[i]=dBs[i]+getARate(OCTAVE_BAND[i]);
        	sum+=Math.pow(10, dBAs[i]/10);
        }
        double spl=10*Math.log10(sum);
        //System.out.println(spl);
        /*if(spl>=40){
        	System.out.println("****"+spl+":");
        	for(int i=0;i<A.length;i++){
    			System.out.println(i+":"+A[i]);
    		}
        	System.out.println("------------------");
        }*/
		return spl;
	}
	
	private double[] getDBs(double[] A,int FFTPoints){
		int band_num=OCTAVE_BAND.length;
		float frequencePerPoint=sampleRate/FFTPoints; //每个点之间的频率差
		double DBs[]=new double[band_num];
		double sum[]=new double[band_num];     //一个频带内频点对应幅度值的平方和
		int num_f[]=new int[band_num];        //一个频带内频点个数
		for(int i=0;i<A.length;i++){	
			double a=i*frequencePerPoint;     //频率
			for(int j=0;j<band_num;j++){			
				if(a<=OCTAVE_BAND[j]){				
					sum[j]+=A[i]*A[i];
					num_f[j]++;
					break;
				}
			}
		}
		for(int i=0;i<band_num;i++){
			if(num_f[i]!=0){
				DBs[i]=10*Math.log10(sum[i]/num_f[i]);
			}	
		}
		return DBs;
	}
	
	private double getARate(double f){   //计算A率
		double R=Math.pow(12200, 2)*Math.pow(f, 4)/((f*f+20.6*20.6)*Math.sqrt((f*f+107.7*107.7)*(f*f+737.9*737.9))*(f*f+12200*12200));
		double A=2.0+20*Math.log10(R);
		return A;
	}
	
	private double[] getAbs(Complex x[]){//TODO
		int N=x.length; 
		double[] A=new double[N];
		for(int i=0;i<x.length;i++){   //幅度值 转化为某频率上的声压
			if(i==0){
				A[i]=x[i].abs()/N;
			}else{
				A[i]=x[i].abs()/(N/2);
			}
		}
		return A;
	}
	
	private Complex[] getHalfPoints(Complex[] x){            //得到FFT计算后的前一半数据，因为FFT计算结果对称
		int half_length=x.length/2;
		Complex result[]=new Complex[half_length];
		for(int i=0;i<half_length;i++){
			result[i]=x[i];
		}
		return result;
	}
	
	private Complex[] toComplex(int[] data){
		int N=data.length;             //fft点数  
		Complex[] x=new Complex[N];    
		for(int i=0;i<N;i++){
			x[i]=new Complex(data[i],0);     
		}
		return x;
	}
	
}
